/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.tabbedproperties.section;

import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.ClassifierTemplateParameter;
import org.eclipse.uml2.uml.ConnectableElementTemplateParameter;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OperationTemplateParameter;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.TemplateableElement;
import org.eclipse.uml2.uml.UMLPackage;

import com.cea.papyrus.core.commands.factories.UMLDi2ElementDeleteFactory;
import com.cea.papyrus.core.editor.CommandStackUtils;
import com.cea.papyrus.core.editpart.IUMLElementEditPart;
import com.cea.papyrus.core.listener.UmlElementListener;
import com.cea.papyrus.core.tabbedproperties.PropertyViewSection;
import com.cea.papyrus.core.tabbedproperties.composite.DecoratedTextComposite;
import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.classdiagram.commands.ElementOwnedByATemplateParameterCreateCommand;
import com.cea.papyrus.diagram.classdiagram.editpart.RedefinableTemplateSignatureEditPart;
import com.cea.papyrus.diagram.classdiagram.editpart.TemplateParameterEditPart;
import com.cea.papyrus.diagram.classdiagram.editpart.TemplateSignatureEditPart;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;
import com.cea.papyrus.profile.ui.dialogs.ChooseSetAssistedDialog;
import com.cea.papyrus.umlutils.Element;

/**
 * The template signature section on the element tab.
 * This section is added only when a TemplateableElement owns a TemplateSignature
 * (cf. TemplateSignatureSectionFilter)
 */
public class OwnedParameteredElementSection extends PropertyViewSection {

	/**
	 * 
	 */
	private DecoratedTextComposite ownedParameteredElementComposite;
	

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#createControls(org.eclipse.swt.widgets.Composite, org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
	 */
	/**
	 * 
	 * 
	 * @param tabbedPropertySheetPage 
	 * @param parent 
	 */
	@Override
	public void createControls(Composite parent,
			TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		
		final TabbedPropertySheetPage sheetPage = tabbedPropertySheetPage ;
		// creation of the ownedParameteredElement section
		ownedParameteredElementComposite = new DecoratedTextComposite("Owned parametered element") {
			
			public void editText() {
				TemplateParameter currentTemplateParameter = (TemplateParameter)getElement().getUml2Element() ;
				if (currentTemplateParameter.getParameteredElement()!=null) {
					EditPart selection = null ;
					for (Iterator<EditPart> i=LookForElement.getAllOutlineEditParts().iterator() ; i.hasNext() ; ) {
						EditPart current = i.next() ;
						if (current.getModel() == currentTemplateParameter.getParameteredElement())
							selection = current ;
					}
					if (selection != null)
						sheetPage.selectionChanged(getPart(), new StructuredSelection(selection)) ;
				}
			}
			
			public void removeButtonPressed() {
				TemplateParameter currentTemplateParameter = (TemplateParameter)this.getElement().getUml2Element() ;
				if (currentTemplateParameter.getOwnedParameteredElement() != null ) {
					CommandStack stack = CommandStackUtils.getCommandStack();
					org.eclipse.gef.commands.Command command = UMLDi2ElementDeleteFactory.eINSTANCE.createCommand(currentTemplateParameter.getOwnedParameteredElement()) ;
					Assert.isNotNull(stack, "Impossible to adapt current editor into a CommandStack");
					stack.execute(command);
					refresh() ;
					if ((graphicalElement != null )&&(graphicalElement instanceof TemplateParameterEditPart)) {
						for (Iterator<EditPart> i = LookForElement.getAllEditParts(((EditPart)graphicalElement).getRoot()).iterator() ; i.hasNext() ; ) {
							EditPart current = i.next() ;
							if (current instanceof TemplateParameterEditPart) {
								if (((TemplateParameterEditPart)current).getUmlElement() == currentTemplateParameter) {
									current.refresh() ;
								}
							}
						}
					}
				}
			}
			
			public void addButtonPressed() {
				TemplateParameter currentTemplateParameter = (TemplateParameter)this.getElement().getUml2Element() ;
				ChooseFilteredMetaclassDialog dialog ; 
				if (currentTemplateParameter instanceof ClassifierTemplateParameter) {
					dialog = new ChooseFilteredMetaclassDialog(composite.getShell(), 
												"Kind of owned parametered classifier to create:", 
												"Selected metaclass:",
												UMLPackage.eINSTANCE.getClassifier());
				}
				else if (currentTemplateParameter instanceof OperationTemplateParameter) {
					dialog = new ChooseFilteredMetaclassDialog(composite.getShell(), 
							"Kind of owned parametered operation to create:", 
							"Selected metaclass:",
							UMLPackage.eINSTANCE.getOperation());
				}
				else if (currentTemplateParameter instanceof ConnectableElementTemplateParameter) {
					dialog = new ChooseFilteredMetaclassDialog(composite.getShell(), 
							"Kind of owned parametered connectable element to create:", 
							"Selected metaclass:",
							UMLPackage.eINSTANCE.getConnectableElement());
				}
				else 
					dialog = new ChooseFilteredMetaclassDialog(composite.getShell(), 
							"Kind of owned parametered element to create:", 
							"Selected metaclass:",
							UMLPackage.eINSTANCE.getParameterableElement());
				dialog.create();
				dialog.setFocus();
				dialog.open();
				if(dialog.getSelectedMetaClass()!=null) {
					// an input string dialog is created to get a default name for the created owned parametered element
					String announce = "Enter a name for the owned parametered " + dialog.getSelectedMetaClass().getName() + " to be created:" ;
					// the owned parametered element is createds
					org.eclipse.gef.commands.Command command ;
					CommandStack stack = CommandStackUtils.getCommandStack();
					Class selectedMetaclass = null ;
					try {
						selectedMetaclass = Class.forName("org.eclipse.uml2.uml." + dialog.getSelectedMetaClass().getName()) ;
					}
					catch (Exception e) {}
					command = new ElementOwnedByATemplateParameterCreateCommand(dialog.getSelectedMetaClass() , selectedMetaclass, currentTemplateParameter, ElementOwnedByATemplateParameterCreateCommand.OWNED_PARAMETERED_ELEMENT) ;
					Assert.isNotNull(stack, "Impossible to adapt current editor into a CommandStack");
					stack.execute(command);
					refresh();
					
					if ((graphicalElement != null )&&(graphicalElement instanceof TemplateParameterEditPart)) {
						for (Iterator<EditPart> i = LookForElement.getAllEditParts(((EditPart)graphicalElement).getRoot()).iterator() ; i.hasNext() ; ) {
							EditPart current = i.next() ;
							if (current instanceof TemplateParameterEditPart) {
								if (((TemplateParameterEditPart)current).getUmlElement() == currentTemplateParameter) {
									TemplateParameterEditPart currentTemplateParameterEditPart = (TemplateParameterEditPart)current ;
									UmlElementListener _adapter=new UmlElementListener((TemplateParameterEditPart)current) ;
									((Notifier)currentTemplateParameter.getOwnedParameteredElement()).eAdapters().add(_adapter) ;
									current.refresh() ;
								}
							}
						}
					}
					
					
//					currentTemplateParameter = (TemplateParameter)this.getElement().getUml2Element();
//					NamedElement createdElement = (NamedElement)currentTemplateParameter.createOwnedParameteredElement(dialog.getSelectedMetaClass()) ;
//					((NamedElement)createdElement).setName(defaultNameDialog.getValue()) ;
				}
			}
			
			public void refresh() {
				if (text.isDisposed()) return ;
				TemplateParameter currentTemplateParameter = (TemplateParameter)this.getElement().getUml2Element() ;
				String elementName = "" ;
				boolean enableControl = true ;
				
				if (graphicalElement != null && graphicalElement instanceof TemplateParameterEditPart) {
					// this test determines if currentTemplateParameter is displayed in a context where it is owned, or in a context where it is referenced
					// if it is referenced, related constrol (add, remove, etc.) must be disabled
					TemplateParameterEditPart editPart = (TemplateParameterEditPart)graphicalElement;
					Uml1SemanticModelBridge semanticModel ;
					if (editPart.getParent().getParent() instanceof RedefinableTemplateSignatureEditPart) {
						RedefinableTemplateSignatureEditPart toto = (RedefinableTemplateSignatureEditPart)editPart.getParent().getParent() ;
						semanticModel = (Uml1SemanticModelBridge)((GraphElement)toto.getGraphNode().getSemanticParent()).getSemanticModel() ;
					}
					else {
						TemplateSignatureEditPart toto = (TemplateSignatureEditPart)editPart.getParent().getParent() ;
						semanticModel = (Uml1SemanticModelBridge)((GraphElement)toto.getGraphNode().getSemanticParent()).getSemanticModel() ;
					}
					if (!((TemplateableElement)semanticModel.getElement()).getOwnedTemplateSignature().getOwnedParameters().contains(currentTemplateParameter)) {
						enableControl = false ;
					}
				}
				if (currentTemplateParameter.getParameteredElement()!=null && currentTemplateParameter.getOwnedParameteredElement()==null) {
					this.addButton.setEnabled(false) ;
					this.removeButton.setEnabled(false) ;
					this.label.setEnabled(false) ;
					this.text.setEnabled(false) ;
				}
				else {
					this.addButton.setEnabled(enableControl) ;
					this.removeButton.setEnabled(enableControl) ;
					this.label.setEnabled(enableControl) ;
					this.text.setEnabled(enableControl) ;
				}
				if (currentTemplateParameter.getOwnedParameteredElement() != null) {
					NamedElement parameteredElement = (NamedElement)currentTemplateParameter.getOwnedParameteredElement();
					if (parameteredElement.getName()== "")
						elementName = "<UNDEFINED>" ;
					else
						elementName = parameteredElement.getName() ;
				}
				if (elementName != null)
					this.text.setText(elementName) ;
				else
					this.text.setText("") ;
			}
		};
		ownedParameteredElementComposite.createContent(parent, tabbedPropertySheetPage.getWidgetFactory());
	}

	/*
	 * @see org.eclipse.ui.views.properties.tabbed.view.ITabbedPropertySection#refresh()
	 */
	/**
	 * 
	 */
	@Override
	public void refresh() {
		ownedParameteredElementComposite.refresh();
//		if ((graphicalElement != null )&&(graphicalElement instanceof TemplateParameterEditPart)) {
//			((TemplateParameterEditPart) graphicalElement).refresh();
//		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#setInput(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
	 */
	/**
	 * 
	 * 
	 * @param part 
	 * @param selection 
	 */
	@Override
	public void setInput(IWorkbenchPart part, ISelection selection) {
		super.setInput(part, selection);
		Assert.isTrue(selection instanceof IStructuredSelection);
		Object input = ((IStructuredSelection) selection).getFirstElement();
		if (input instanceof IUMLElementEditPart) {
			org.eclipse.uml2.uml.Element element = ((IUMLElementEditPart) input).getUmlElement();
        	if(element instanceof org.eclipse.uml2.uml.TemplateParameter) {
        		Element utilElement = new Element((org.eclipse.uml2.uml.TemplateParameter)element);
        		ownedParameteredElementComposite.setElement(utilElement) ;
        	}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.properties.tabbed.PropertyViewSection#dispose()
	 */
	/**
	 * 
	 */
	public void dispose(){
		super.dispose();
		if(ownedParameteredElementComposite!=null)
			ownedParameteredElementComposite.dispose();
	}
	
	// ChooseSetAssistedDialog is specialized locally
	protected class ChooseFilteredMetaclassDialog extends ChooseSetAssistedDialog {
		
		private String selectedClassifierName ;
		
		public ChooseFilteredMetaclassDialog(Shell parentShell, String possibleText, String selectedText, EClass filter){
			super(parentShell, possibleText, selectedText) ;
			List filteredMetaclasses = LookForElement.getMetaclasses(filter,false, getElement()) ;
			for (Iterator<Classifier> i = filteredMetaclasses.iterator() ; i.hasNext() ; ){
				Classifier current = i.next();
				if(!selectedElementList.contains(current)) {
					possibleElementList.addElement(current.getName());
				}
			}
		}
		
		// create method is overrided so that up and down buttons are not visible
		// Only one metaclass can be selected, so these features are useless
		public void create() {
			super.create() ;
			downButton.setVisible(false) ;
			upButton.setVisible(false) ;
		}
			
		public void runActionAdd(Object element) {
			super.runActionAdd(element) ;
			selectedClassifierName = new String((String)element) ;
			this.addButton.setEnabled(false) ;
		}
		
		protected void runActionRemove(Object element){
			super.runActionRemove(element) ;
			this.addButton.setEnabled(true) ;
			this.selectedClassifierName = null ;
		}
	
		public void okPressed() {
			if (selectedClassifierName!=null)
				super.okPressed() ;
		}
		
		public void cancelPressed() {
			selectedClassifierName = null ;
			super.cancelPressed() ;
		}
		
		public EClass getSelectedMetaClass() {
			if (selectedClassifierName == null)
				return null ;
			else {
				return (EClass)UMLPackage.eINSTANCE.getEClassifier(selectedClassifierName) ;
			}
		}
		
	}
	
}

